﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SwitchMiner.Interfaces;
using System.IO;
using System.Reflection;
using SwitchMiner.Controlers;
using SwitchMiner.Models;
using System.Threading;
using System.Diagnostics;

namespace SwitchMiner
{
    public partial class MainSwitchMiner : Form, IModelNotification
    {
        private string pathToMinersModel        = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Miners.csv");
        private string pathToParametersModel    = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Parameters.csv");
        private string pathToSwitchModel        = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Switch.csv");

        private bool bCancelCurrentJob          = false;

        private MinersControler     minerControler;
        private ParametersControler parameterControler;
        private SwitchControler     switchControler;

        private List<MinerModel>    minerListModel      = new List<MinerModel>();
        private List<ParameterModel> parameterListModel = new List<ParameterModel>();
        private List<SwitchModel>   switchListModel     = new List<SwitchModel>();
        public MainSwitchMiner()
        {
            InitializeComponent();
        }

        private void MainSwitchMiner_Load(object sender, EventArgs e)
        {
            if (File.Exists(pathToMinersModel) == true)
            {
                minerListModel = ConfigManager.LoadMiners(pathToMinersModel);
            }
            minerControler = new MinersControler(this, minerListModel);

            if (File.Exists(pathToParametersModel) == true)
            {
                parameterListModel = ConfigManager.LoadParameters(pathToParametersModel);
            }

            parameterControler = new ParametersControler(this, parameterListModel);

            if (File.Exists(pathToSwitchModel) == true)
            {
                switchListModel = ConfigManager.LoadSwitch(pathToSwitchModel);
            }

            switchControler = new SwitchControler(this, switchListModel);
        }


        private void butAddMinerParameter_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(txtParametersName.Text) == true)
            {
                MessageBox.Show("Cannot add this Parameter because the parameter Name is empty", "Parameter name not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            parameterControler.AddParameter(new ParameterModel(txtParametersName.Text, txtParametersValue.Text));
            saveConfigs();
        }

        private void butDeleteMinerParameter_Click(object sender, EventArgs e)
        {
            deleteSelectedParameterItem();
        }
        private void deleteSelectedParameterItem()
        {
            if (listMinerParameters.SelectedIndex > -1)
            {
                ParameterModel selectedItem = (ParameterModel)listMinerParameters.Items[listMinerParameters.SelectedIndex];
                parameterControler.RemoveParameter(selectedItem);
                saveConfigs();
            }
        }

        private void deleteSelectedSwitchItem()
        {
            if (listSwitch.SelectedIndex > -1)
            {
                SwitchModel selectedItem = (SwitchModel)listSwitch.Items[listSwitch.SelectedIndex];
                switchControler.RemoveModel(selectedItem);
                saveConfigs();
            }
        }

        private void butAddMiner_Click(object sender, EventArgs e)
        {
            if (File.Exists(txtMinerPath.Text) == false)
            {
                MessageBox.Show("Cannot add this miner because it's path " + txtMinerPath.Text + " doesn't exist.", "Miner path not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (String.IsNullOrEmpty(txtMinerName.Text) == true)
            {
                MessageBox.Show("Cannot add this miner because the miner Name is empty", "Miner name not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            minerControler.AddMiner(new MinerModel(txtMinerName.Text, txtMinerPath.Text));
            saveConfigs();
        }

        private void butSwitchAdd_Click(object sender, EventArgs e)
        {
            if( String.IsNullOrEmpty(txtSwitchDuration.Text))
            {
                MessageBox.Show("Text field Duration is empty", "Invalid Input", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (comboSwitchMinersList.SelectedIndex == -1 || comboSwitchMinersParameters.SelectedIndex == -1)
            {
                MessageBox.Show("Either Miner or Parameter combo box is not selected, please make sure you selected a proper configuration", "Invalid Input", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            long lDuration = 60;
            long.TryParse(txtSwitchDuration.Text, out lDuration);
            if (lDuration <= 0)
            {
                MessageBox.Show("Text field Duration must be higer than 0", "Invalid Input", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            switchControler.AddModel(new SwitchModel(comboSwitchMinersList.Items[comboSwitchMinersList.SelectedIndex].ToString(),
                                                     comboSwitchMinersParameters.Items[comboSwitchMinersParameters.SelectedIndex].ToString(),
                                                     lDuration));
            saveConfigs();
        }

        private void deleteSelectedMinerItem()
        {
            if (listMiners.SelectedIndex > -1)
            {
                MinerModel selectedItem = (MinerModel)listMiners.Items[listMiners.SelectedIndex];
                minerControler.RemoveMiner(selectedItem);
                saveConfigs();
            }
        }
        private void butDeleteMiner_Click(object sender, EventArgs e)
        {
            deleteSelectedMinerItem();
        }

        private void listMiners_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listMiners.SelectedIndex > -1)
            {
                MinerModel selectedmodel = (MinerModel)(listMiners.Items[listMiners.SelectedIndex]);
                txtMinerName.Text = selectedmodel.MinerName;
                txtMinerPath.Text = selectedmodel.MinerPath;
            }
        }


        private void listMinerParameters_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listMinerParameters.SelectedIndex > -1)
            {
                ParameterModel selectedmodel = (ParameterModel)(listMinerParameters.Items[listMinerParameters.SelectedIndex]);
                txtParametersName.Text = selectedmodel.Name;
                txtParametersValue.Text = selectedmodel.Parameters;
            }
        }
        private void saveConfigs()
        {
                ConfigManager.SaveMinerConfig(pathToMinersModel, minerControler.GetModel());
                ConfigManager.SaveParametersConfig(pathToParametersModel, parameterControler.GetModel());
                ConfigManager.SaveSwitchConfig(pathToSwitchModel, switchControler.GetModel());
        }

        private void butBrowseMiner_Click(object sender, EventArgs e)
        {
            openFileDialogMinerPath.ShowDialog();
            if (String.IsNullOrEmpty(openFileDialogMinerPath.FileName))
            {
                return; 
            }
            if (File.Exists(openFileDialogMinerPath.FileName))
            {
                txtMinerPath.Text = openFileDialogMinerPath.FileName;
            }

        }

        private void listMiners_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                deleteSelectedMinerItem();
            }
        }
        private void listSwitch_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                deleteSelectedSwitchItem();
            }
        }

        private void listMinerParameters_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                deleteSelectedParameterItem();
            }
        }


        void IModelNotification.ParametersModelsChanged(List<Models.ParameterModel> newModel)
        {
            listMinerParameters.Items.Clear();
            comboSwitchMinersParameters.Items.Clear();
            foreach (Models.ParameterModel model in newModel)
            {
                listMinerParameters.Items.Add(model);
                comboSwitchMinersParameters.Items.Add(model);
            }
        }

        void IModelNotification.MinerModelsChanged(List<MinerModel> newModel)
        {
            listMiners.Items.Clear();
            comboSwitchMinersList.Items.Clear();
            foreach (MinerModel model in newModel)
            {
                listMiners.Items.Add(model);
                comboSwitchMinersList.Items.Add(model);
            }
        }
        void IModelNotification.SwitchModelsChanged(List<SwitchModel> newModel)
        {
            listSwitch.Items.Clear();
            foreach (SwitchModel model in newModel)
            {
                listSwitch.Items.Add(model);
            }
        }

        private void butSwitchMoveUp_Click(object sender, EventArgs e)
        {
            if (listSwitch.SelectedIndex == -1 || listSwitch.SelectedIndex == 0)
            {
                return;
            }

        }

        private void butSwitchStart_Click(object sender, EventArgs e)
        {
            if (switchControler.GetModel().Count == 0)
            {
                return;
            }
            bCancelCurrentJob = false;
            butSwitchStart.Enabled  = false;
            butSwitchStop.Enabled   = true;
            listSwitch.Enabled      = false;
            int idx = 0;
            while(bCancelCurrentJob == false)
            {
                OverallProgress.Value = (int)(idx * 100 / switchControler.GetModel().Count);
                listSwitch.SelectedIndex = idx;
                MinerModel minerModel           = minerControler.GetModelFromName(switchControler.GetModel()[idx].MinerName);
                ParameterModel parameterModel   = parameterControler.GetModelFromName(switchControler.GetModel()[idx].ParameterName);
                if(minerModel != null && parameterModel != null)
                {
                    if(File.Exists(minerModel.MinerPath) == true)
                    {
                        startJob(minerModel.MinerPath, parameterModel.Parameters, switchControler.GetModel()[idx].Duration);
                    }
                }

                idx++;
                if (idx > (switchControler.GetModel().Count - 1))
                {
                    idx = 0;
                }
            }

            butSwitchStart.Enabled  = true;
            butSwitchStop.Enabled   = false;
            listSwitch.Enabled      = true;
        }
        private void KillAlreadyRunningProcess(string processName)
        {
            Process[] processes = Process.GetProcesses();
            foreach (var proc in processes)
            {
                if (processName.ToLower().Contains(proc.ProcessName.ToLower()))
                {
                    try
                    {
                        proc.CloseMainWindow();
                        Thread.Sleep(5000);
                        proc.Close();
                        Thread.Sleep(1000);
                        proc.Kill();
                        Thread.Sleep(1000);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("An error Occured when attempting to kill existing process " + processName + " : " + ex.Message, "Application interruption error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }
        private System.Diagnostics.Process StartApp(string pathtoMiner, string parameters, bool killAlreadyRunningProcess)
        {
            if( true == killAlreadyRunningProcess)
            {
                string appName = Path.GetFileName(pathtoMiner).ToLower();
                KillAlreadyRunningProcess(appName);
            }

            System.Diagnostics.Process process = new System.Diagnostics.Process();
            //process.StartInfo.FileName = @"C:\WINDOWS\system32\iisreset.exe";
            process.StartInfo.FileName = pathtoMiner;
            process.StartInfo.Arguments = parameters;
            process.StartInfo.UseShellExecute = true;
            process.StartInfo.CreateNoWindow = false;
            process.StartInfo.RedirectStandardError = false;
            process.StartInfo.RedirectStandardOutput = false;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
            process.Start();

            return process;
            
        }

        private void startJob(string pathtoMiner, string parameters, long duration)
        {
            long durationInSeconds = duration * 60;
            long remainingDuration = durationInSeconds;

            BackgroundWorker bw = new BackgroundWorker();
            // this allows our worker to report progress during work
            bw.WorkerReportsProgress = true;
            CurrentProgress.Value = 0;

            // what to do in the background thread
            bw.DoWork += new DoWorkEventHandler(
            delegate(object o, DoWorkEventArgs args)
            {
                BackgroundWorker b = o as BackgroundWorker;
                //run application here
                System.Diagnostics.Process proc = StartApp(pathtoMiner, parameters, this.checkKillSameProcess.Checked);
                // do some simple processing for 10 seconds
                while (remainingDuration > 0 && bCancelCurrentJob == false && proc.HasExited == false)
                {
                    // report the progress in percent
                    b.ReportProgress((int)(((durationInSeconds) - remainingDuration) * 100 / (durationInSeconds)));
                    remainingDuration--;
                    Application.DoEvents();
                    Thread.Sleep(1000);
                }
                try
                {
                    if (proc.HasExited == false)
                    {
                        proc.CloseMainWindow();
                        Thread.Sleep(5000);
                        proc.Close();
                        Thread.Sleep(1000);
                        proc.Kill();
                    }
                }
                catch (Exception)
                {
                }
            });
            // what to do when progress changed (update the progress bar for example)
            bw.ProgressChanged += new ProgressChangedEventHandler(
            delegate(object o, ProgressChangedEventArgs args)
            {
                CurrentProgress.Value = args.ProgressPercentage;
                Application.DoEvents();
            });

            // what to do when worker completes its task (notify the user)
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
            delegate(object o, RunWorkerCompletedEventArgs args)
            {
                CurrentProgress.Value = 100;
                Application.DoEvents();
            });

            bw.RunWorkerAsync();

            while (bw.IsBusy == true)
            {
                Thread.Sleep(100);
                Application.DoEvents();
            }
            bw.Dispose();
        }

        private void butSwitchStop_Click(object sender, EventArgs e)
        {
            bCancelCurrentJob = true;
        }


        private void txtDonationBitcoins_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.ControlKey && e.KeyCode != Keys.C)
            {
                e.SuppressKeyPress = true;
            }
        }

        private void txtDonationLightcoins_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.ControlKey && e.KeyCode != Keys.C)
            {
                e.SuppressKeyPress = true;
            }
        }

        private void txtDonationTips_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.ControlKey && e.KeyCode != Keys.C)
            {
                e.SuppressKeyPress = true;
            }
        }

        private void txtDonationDodge_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.ControlKey && e.KeyCode != Keys.C)
            {
                e.SuppressKeyPress = true;
            }
        }




        

        

        

        
    }

}
